/* dgl.c -- A implemention of DGL procol 
   Copyright (C) 2007 Libo Jiao

This file is part of GS.
The Gas Server is software of Gas Server solution.*/

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>

#include "dgl.h"

#define POSIX_TERMIOS 1

static int fd_dgl;
/*
 * Set baudrate, parity and number of bits.
 */
static void setparms(int fd, char *baudr, char *par, char *bits, char *stopb,
                int hwf, int swf)
{
  int spd = -1;
  int newbaud;
  int bit = bits[0];

  struct termios tty;

  tcgetattr(fd, &tty);

  /* We generate mark and space parity ourself. */
  if (bit == '7' && (par[0] == 'M' || par[0] == 'S'))
    bit = '8';

  /* Check if 'baudr' is really a number */
  if ((newbaud = (atol(baudr) / 100)) == 0 && baudr[0] != '0')
    newbaud = -1;

  switch (newbaud) {
    case 0:
#ifdef B0
      spd = B0;
#else
      spd = 0;
#endif
      break;
    case 3:	spd = B300;	break;
    case 6:	spd = B600;	break;
    case 12:	spd = B1200;	break;
    case 24:	spd = B2400;	break;
    case 48:	spd = B4800;	break;
    case 96:	spd = B9600;	break;
#ifdef B19200
    case 192:	spd = B19200;	break;
#else /* B19200 */
#  ifdef EXTA
    case 192:	spd = EXTA;	break;
#   else /* EXTA */
    case 192:	spd = B9600;	break;
#   endif /* EXTA */
#endif	 /* B19200 */
#ifdef B38400
    case 384:	spd = B38400;	break;
#else /* B38400 */
#  ifdef EXTB
    case 384:	spd = EXTB;	break;
#   else /* EXTB */
    case 384:	spd = B9600;	break;
#   endif /* EXTB */
#endif	 /* B38400 */
#ifdef B57600
    case 576:	spd = B57600;	break;
#endif
#ifdef B115200
    case 1152:	spd = B115200;	break;
#endif
#ifdef B230400
    case 2304:	spd = B230400;	break;
#endif
  }

#ifdef POSIX_TERMIOS

  if (spd != -1) {
    cfsetospeed(&tty, (speed_t)spd);
    cfsetispeed(&tty, (speed_t)spd);
  }

  switch (bit) {
    case '5':
      tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS5;
      break;
    case '6':
      tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS6;
      break;
    case '7':
      tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS7;
      break;
    case '8':
    default:
      tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
      break;
  }
  /* Set into raw, no echo mode */
  tty.c_iflag =  IGNBRK;
  tty.c_lflag = 0;
  tty.c_oflag = 0;
  tty.c_cflag |= CLOCAL | CREAD;
#ifdef _DCDFLOW
  tty.c_cflag &= ~CRTSCTS;
#endif
  tty.c_cc[VMIN] = 1;
  tty.c_cc[VTIME] = 5;

  if (swf)
    tty.c_iflag |= IXON | IXOFF;
  else
    tty.c_iflag &= ~(IXON|IXOFF|IXANY);

  tty.c_cflag &= ~(PARENB | PARODD);
  if (par[0] == 'E')
    tty.c_cflag |= PARENB;
  else if (par[0] == 'O')
    tty.c_cflag |= (PARENB | PARODD);

  if (stopb[0] == '2')
    tty.c_cflag |= CSTOPB;
  else
    tty.c_cflag &= ~CSTOPB;

  tcsetattr(fd, TCSANOW, &tty);

#endif /* POSIX_TERMIOS */
}

static unsigned char xorsum(unsigned char *buff, int start, int end)
{
	int i;
	unsigned char value = 0X0;
	printf ("22222222222222\n");
	for (i = start; i < end; i++)
		value ^= buff[i];
		
    printf ("1111111111111111111\n");
	return value & 0X7F;
}

static void timer_handler(int signum)
{
    // printf ("timerover %d\n", (int) time((time_t*) NULL));
    int ret;
    static int index;
    unsigned char buf[4];
    // GS_TANK* tank;


    // tank = &g_gs.tanks[index];

    // ret = gs_tank_get_addr(tank, &buf[0]);
    buf[0] = 131;

    buf[1] = 0x16;
    buf[2] = 0x00;
    buf[3] = (buf[0] ^ buf[1] ^ buf[2]) & 0x7f;

    write(fd_dgl, buf,sizeof(buf));

    printf ("output buf = %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
    // index = (index + 1) % g_gs.tanks_nr;

}

static void init_sigaction(void)
{
    int ret;
    struct sigaction act;
    act.sa_handler=timer_handler;
    act.sa_flags=0;
    sigemptyset(&act.sa_mask);
    ret = sigaction(SIGALRM, &act, NULL);
    if(ret != 0)
        perror("sigaction");
}

static void init_timer(void)
{
    int ret;
    struct itimerval value, old_value;
    value.it_value.tv_sec=0;
    value.it_value.tv_usec=900000;
    value.it_interval=value.it_value;

    ret = setitimer(ITIMER_REAL, &value, &old_value); 
    if (ret != 0) 
        perror("setitimer");
}

int gs_dgl_init(void)
{
    // TODO
    char* dev = "/dev/ttyS1";

    fd_dgl = open (dev, O_RDWR | O_NONBLOCK);
   	if (fd_dgl == -1) {
	   perror ("open");
	   return -1;
	}

	setparms(fd_dgl, "4800", "O", "8", "1", 0, 0);

    init_sigaction();
    init_timer();
    return 0;
}

int gs_dgl_wait(void)
{
    // TODO
    int ready = 0;
    fd_set in;

    FD_ZERO(&in);
    FD_SET(fd_dgl, &in);

    ready = select (fd_dgl + 1, &in, NULL, NULL, NULL);

   //  printf ("%s select return \n", __FUNCTION__);

    if (ready < 0)
    {
        //perror ("select return");
        return -1;
    }
    else
    {
        return 0;
    }
}

int gs_dgl_data(DGL_DATA *data)
{
    // TODO
    unsigned char buf[24];
    static int bytes;

    int i=0, n=0;

    if (data == NULL) {
        // fprintf (stderr, "DATA IS NULL\n");
        return -1;
    }

   printf ("in %s %s\n", __FILE__, __FUNCTION__);

        printf ("bytes = %d\n", bytes);
    while ((n = read(fd_dgl, &buf[bytes], 24)) > 0)
    {
        printf ("n = %d\n", n);
        
        bytes += n;
        printf ("bytes = %d\n", bytes);
        
        if (bytes > 23) {
            bytes = 0;
            printf ("dddddddddddddddddddd\n");
        }

        if (bytes >= 12)
        {
            printf("aaaaaaaaaaaa\n");

            for (i=0; i<12; i++) {
				if ((buf[i] & 0x80) && (buf[i+1] == 0x16) && (
							buf[i+2] == 8) && buf[11] == xorsum(buf, i, i+11))
				{

					data->addr = buf[i];
					data->oil = ((((buf[i+5] << 7) | buf[i+4]) << 7) | buf[i+3]) * 0.01;
					data->water = ((((buf[i+8] << 7) | buf[i+7]) << 7) | buf[i+6]) * 0.01;
					data->temp = (((buf[i+10] << 7) | buf[i+9]) >> 6) - 50;

					bytes = 0;

					return 0;
				}
			}
            printf("bbbbbbbbbbbbb\n");
#if 1
            for (i=0; i<11; i++)
                buf[i] = buf[i+1];

#endif
            printf("cccccccccccccccccccc\n");

            return -1;
        }
        printf ("11111111111111111\n");
        printf ("bytes = %d\n", bytes);
    }
    
    return -1;
}

